package org.lanqiao.music.common.utils;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.lanqiao.music.common.exp.RateLimitExceededException;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;


@Aspect
@Component
public class RateLimitAspect {

    private final Map<String, RateLimitInfo> rateLimitMap = new HashMap<>();

    // 切点，匹配所有带有 @RateLimit 注解的方法
    @Around("@annotation(rateLimit)")
    public Object around(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
        String key = getKey(joinPoint);
        RateLimitInfo rateLimitInfo = rateLimitMap.get(key);

        long currentTime = System.currentTimeMillis();
        int limit = rateLimit.limit();
        long timeout = rateLimit.timeout() * 1000; // 转换为毫秒

        if (rateLimitInfo == null || currentTime - rateLimitInfo.startTime > timeout) {
            // 重置限流信息
            rateLimitInfo = new RateLimitInfo(currentTime);
            rateLimitMap.put(key, rateLimitInfo);
        }

        // 清理过期的请求时间戳
        while (!rateLimitInfo.requestTimestamps.isEmpty() &&
                currentTime - rateLimitInfo.requestTimestamps.peek() > timeout) {
            rateLimitInfo.requestTimestamps.poll();
        }

        // 添加当前请求的时间戳
        rateLimitInfo.requestTimestamps.add(currentTime);

        if (rateLimitInfo.requestTimestamps.size() > limit) {
            throw new RateLimitExceededException("请求次数过多，请稍后再试");
        }

        return joinPoint.proceed();
    }

    private String getKey(ProceedingJoinPoint joinPoint) {
        // 可以根据请求参数、用户 ID 等生成唯一标识符
        // 这里简单使用方法名和参数作为标识，可以根据需要进行扩展
        StringBuilder keyBuilder = new StringBuilder(joinPoint.getSignature().toShortString());
        for (Object arg : joinPoint.getArgs()) {
            keyBuilder.append("_").append(arg.toString());
        }
        return keyBuilder.toString();
    }

    private static class RateLimitInfo {
        private long startTime;
        private Queue<Long> requestTimestamps; // 保存请求的时间戳

        public RateLimitInfo(long startTime) {
            this.startTime = startTime;
            this.requestTimestamps = new LinkedList<>();
        }
    }
}
